﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using BibMan.controller;
using BibMan.model;
using BibMan.model.database;
using BibMan.model.database.bibtex;
using System.Drawing;

namespace BibMan.gui {

    public delegate void editHandler();

    public partial class ReferenceTable : DataGridView {

        public event editHandler EditRowStarted;
        private void FireEditRowStarted() {
            if (this.EditRowStarted != null) EditRowStarted();
        }

        public ReferenceTable() {

            InitializeComponent();


            if (this.ColumnCount == 0) {
                this.tagsToShow = new List<String>() {
                    "Id", "Title", "Author", "Pin", "Type", "Year"
                };
                foreach (String t in tagsToShow) {
                    this.AddColumn(t);
                }
            }

            foreach (DataGridViewColumn col in this.Columns) {
                col.SortMode = DataGridViewColumnSortMode.Automatic;
            }

            Model.Instance.DatabaseLoaded += OnDatabaseLoaded;
            Model.Instance.DatabaseCreated += OnDatabaseLoaded;
           

            this.CellDoubleClick += OnDoubleClick;
            this.KeyDown += OnF2;
        }

        public ReferenceTable(IContainer container)
            : this() {
                container.Add(this);
        }
        private List<String> tagsToShow;

        public void OnDatabaseLoaded() {
            Model.Instance.Database.References.Added -= OnReferenceAdded;
            Model.Instance.Database.References.Added += OnReferenceAdded;
            Model.Instance.Database.References.Removed -= OnReferenceRemoved;
            Model.Instance.Database.References.Removed += OnReferenceRemoved;
            Model.Instance.Database.References.Updated -= OnReferenceUpdated;
            Model.Instance.Database.References.Updated += OnReferenceUpdated;
            UnMasc();
        }

        public void AddColumn(String columnName) {
            if (!this.Columns.Contains(columnName)) {
                int i = this.Columns.Add(columnName, columnName);
                //DataGridViewColumn col = this.Columns[i];
                //DataGridViewCell cell = new DataGridViewTextBoxCell();
                //cell.OwningColumn = col;
                //this.RowTemplate.Cells.Add(cell);
            }
        }

        //public void UpdateTable() {
        //    BindingSource bs = new BindingSource();
        //    bs.DataSource = Model.Instance.Database.ToList();
        //    this.DataSource = bs;
        //    this.Sort(this.Columns["Id"], ListSortDirection.Ascending);
        //}

        public DataGridViewRow UpdateRow(DataGridViewRow row, Reference reference) {
            foreach (DataGridViewColumn col in this.Columns) {
                if (col.Name == "Path") {
                    row.Cells[col.Name].Value = reference.Path;
                } else if (col.Name == "Id") {
                    row.Cells[col.Name].Value = reference.Id;
                } else if (col.Name == "Type") {
                    row.Cells[col.Name].Value = reference.BibItem.BibType.ToString();
                } else if (col.Name == "Pin") {
                    StringBuilder temp = new StringBuilder();
                    foreach (String p in reference.Pins) temp.AppendFormat("{0}, ", p);
                    row.Cells[col.Name].Value = reference.Pins.ToString();
                } else {
                    row.Cells[col.Name].Value = reference.BibItem[col.Name];
                }
            }
            return row;
        }

        public void OnReferenceAdded(String id, Reference reference) {
            String[] row = new String[this.Columns.Count];
            int i=0;
            foreach (DataGridViewColumn col in this.Columns) {
                if (col.Name == "Path") {
                    row[i++] = reference.Path;
                } else if (col.Name == "Id") {
                    row[i++] = reference.Id;
                } else if (col.Name == "Type") {
                    row[i++] = reference.BibItem.BibType.ToString();
                } else if (col.Name == "Pin") {
                    StringBuilder temp = new StringBuilder();
                    foreach (String p in reference.Pins) temp.AppendFormat("{0}, ", p);
                    row[i++] = temp.ToString();
                } else {
                    row[i++] = reference.BibItem[col.Name];
                }
            }
            this.Rows.Add(row);
        }

        public void OnReferenceRemoved(String id, Reference reference) {
            for (int i = 0; i < Rows.Count; i++) {
                if (Rows[i].Cells["Id"].Value.Equals(id)) {
                    this.Rows.Remove(Rows[i]);
                }
            }
        }

        public void OnReferenceUpdated(String id, Reference oldReference, Reference newReference) {
            for (int i = 0; i < Rows.Count; i++) {
                if (Rows[i].Cells["Id"].Value.Equals(oldReference.Id)) {
                    UpdateRow(Rows[i], newReference);
                }
            }
        }

        public void OnF2(object sender, KeyEventArgs e) {
            if (e.KeyCode == Keys.F2) {
                LaunchReferenceEditor(this.CurrentRow.Index);
            }
        }
        
        public void OnDoubleClick(object sender, DataGridViewCellEventArgs e) {
            LaunchReferenceEditor(e.RowIndex);
        }

        public void LaunchReferenceEditor(int rowIndex) {
            if (rowIndex < 0) return;
            FireEditRowStarted();
            
            ReferenceEditor editor = new ReferenceEditor();
            String id = this.Rows[rowIndex].Cells["Id"].Value.ToString();
            Console.WriteLine(id);
            editor.Reference = Model.Instance.Database[id];

            DialogResult result = editor.ShowDialog(this);
            if (result.Equals(DialogResult.OK)) {
                //todo what happens when the id gets changed?
                Model.Instance.Database.References.ChangeKey(id, editor.Reference.Id);
                Model.Instance.Database.References[editor.Reference.Id] = editor.Reference;
            }
            editor.Dispose();
        }

        protected void PasteReference(object sender, KeyEventArgs e) {
            if (e.KeyCode == Keys.V && e.Modifiers == Keys.Control) {
                if (Clipboard.ContainsText()) {
                    BibItem bi;
                    if (BibItem.TryParse(Clipboard.GetText(), out bi)) {
                        Reference r = new Reference(bi);
                        ReferenceEditor editor = new ReferenceEditor();
                        editor.Reference = r;
                        DialogResult result = editor.ShowDialog(this);
                        if (result.Equals(DialogResult.OK)) {
                            Model.Instance.Database.References.Add(editor.Reference.Id, editor.Reference);
                        }
                        editor.Dispose();
                    } else {
                        MessageBox.Show("Could not parse the pasted text.");
                    }
                }
            }
        }

        public void Masc(IEnumerable<String> Ids) {
            this.Rows.Clear();
            foreach (String id in Ids) {
                OnReferenceAdded(id, Model.Instance.Database[id]);
            }
        }

        public void UnMasc() {
            this.Rows.Clear();
            foreach (Reference r in Model.Instance.Database) {
                OnReferenceAdded(r.Id, r);
            }
        }

        //todo use this code in context menu
        public void OpenPDF(int rowIndex) {
            String id = this.Rows[rowIndex].Cells["Id"].Value.ToString();
            //System.Diagnostics.Process.Start(Model.Instance.Database[id].Path);
        }

        private void RightClick(object sender, DataGridViewCellMouseEventArgs e) {
            if (e.RowIndex < 0) {
                this.ContextMenuStrip = this.headerContextMenu;
            } else if (e.ColumnIndex < 0) {
                this.ContextMenuStrip = null;
            } else {
                this.ContextMenuStrip = this.cellContextMenu;
            }
        }

        //todo stop this using literal strings
        private void cellContextItemClicked(object sender, ToolStripItemClickedEventArgs e) {
            if (e.ClickedItem.Text.Equals("Open")) {
                OpenPDF(this.CurrentRow.Index);
            } else if (e.ClickedItem.Text.Equals("Preferences")) {
                LaunchReferenceEditor(this.CurrentRow.Index);
            }
        }

    }
}